package org.property.path;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.property.gui.Form;
import org.property.gui.PropertiesData;

/**
 * @author Yaroslav Boichuk
 * @since 26.08.09
 * 
 *        Class for working with properties. Can add property to file, remove
 *        from it.
 * 
 * 
 */
public class ClientHandler implements IClientHandler {

	private String PATH_SEPARATOR = PathScanner.PATH_SEPARATOR;

	private static Logger log = Logger.getLogger(ClientHandler.class);

	// remove property from file
	public void removeProperty(File file, String key) {

		Properties props = new Properties();

		FileInputStream input;
		FileOutputStream output;

		try {

			input = new FileInputStream(file);
			props.load(input);
			input.close();

			if (checkKey(file, key) == true) {
				output = new FileOutputStream(file);
				// remove key from map
				props.remove(key);
				props.store(output, null);
				log.info("Successful removing key=" + key + " from file="
						+ file.toString());
				output.close();
			} else {
				log.warn("Can't find key=" + key + " in file:"
						+ file.toString());
			}

		} catch (FileNotFoundException e) {
			log.info("Can't find file:" + file.toString() + " for key=" + key);
		} catch (IOException e) {
			log.error("Input/output error while trying remove key=" + key
					+ "from file" + file.toString());
		}
	}

	// add new property to file if property isn't exist in file else notify user
	public void addProperty(File file, String key, String property) {
		try {

			// check is property successfully got from file. Else miss setting
			if (property != null) {

				// load file copied from util.Properties, 'cause want to store
				// without header
				MyUtilProperties props = new MyUtilProperties();

				// true = create and append
				boolean createFile = false;

				// check if file is existing
				if (file.isFile() == false) {
					log.warn("File " + file + " doesn't exist");
					createFile = true;
				}

				FileOutputStream fileStream = new FileOutputStream(file, true);
				if (file.isFile() == true && createFile == true) {
					log.info("Created file " + file);
				}

				props.setProperty(key, property);
				log.info("Try to add " + key + "=" + property + " to file:"
						+ file);

				// check if key and property is stored in file
				if (checkKey(file, key) == false) {

					props.store(fileStream, "Auto added by Property Changer");
					log.info("Added: " + key + "=" + property + " to file:"
							+ file);
				} else {
					log.warn("Key:" + key + " is in file:" + file);
				}

				fileStream.close();
			}
		} catch (IOException e) {
			log.error("Input/output error while trying add " + key + "="
					+ property + "to file" + file.toString());
		}
	}

	public void listThroughFiles(String dirNameWithProp,
			PropertiesData propertiesData) {
		File dirChecker = new File(dirNameWithProp);
		if (dirChecker.isDirectory()) {

			// set file to write into key=value
			File fileWriteInto = new File(dirNameWithProp + PATH_SEPARATOR
					+ propertiesData.getPropertyFileInto());

			// set file to get property value from
			File fileGetFrom = new File(dirNameWithProp + PATH_SEPARATOR
					+ propertiesData.getPropertyFileFrom());

			if (propertiesData.isForList() == true) {
				// getting for list
				getForList(propertiesData, fileWriteInto, fileGetFrom);

			} else {

				// choose and
				operationChooser(propertiesData, fileWriteInto, fileGetFrom);
			}
		}
	}

	// inner interface for getting operation choose and than fill list with
	// files name
	public interface IFileOperationHandler {
		public void doOperation(PropertiesData propertiesData,
				File fileWriteInto, File fileGetFrom);
	}

	// inner class provide getting list for files which will be removed
	class RemoveFileOperationHandler implements IFileOperationHandler {
		public void doOperation(PropertiesData propertiesData,
				File fileWriteInto, File fileGetFrom) {
			// if file exists and source key is in it - append fileGetfrom to
			// text area, that it
			// will be changed in future
			if (fileGetFrom.isFile() == true
					&& getPropertyForKey(fileGetFrom, propertiesData
							.getSourceKey()) != null) {
				Form.appendTextToTextList(fileGetFrom.toString() + "\n");
			}
		}
	}

	// inner class provide getting list for files in which will be copied new
	// key
	class CopyFileOperationHandler implements IFileOperationHandler {
		public void doOperation(PropertiesData propertiesData,
				File fileWriteInto, File fileGetFrom) {

			// if file where we get key from is exists and value for source key
			// in fileGetFrom is in it, and destination key with value isn't in
			// file where we will write to - append file to text area, that it
			// will be changed in future
			if (fileGetFrom.isFile() == true
					&& getPropertyForKey(fileGetFrom, propertiesData
							.getSourceKey()) != null
					&& getPropertyForKey(fileWriteInto, propertiesData
							.getDestKey()) == null) {
				Form.appendTextToTextList(fileWriteInto.toString() + "\n");
			}

		}
	}

	// inner class provide getting list for files in which will be moved new key
	class MoveFileOperationHandler implements IFileOperationHandler {
		public void doOperation(PropertiesData propertiesData,
				File fileWriteInto, File fileGetFrom) {
			// if file where we get key from is exists and value for source key
			// in fileGetFrom is in it and value for source key in fileWriteInto
			// isn't - append fileWriteInto to text area, that it
			// will be changed in future
			if (fileGetFrom.isFile() == true
					&& getPropertyForKey(fileGetFrom, propertiesData
							.getSourceKey()) != null
					&& getPropertyForKey(fileWriteInto, propertiesData
							.getSourceKey()) == null) {
				Form.appendTextToTextList(fileWriteInto.toString() + "\n");
			}
		}
	}

	private void getFileName(IFileOperationHandler fileOperation,
			PropertiesData propertiesData, File fileWriteInto, File fileGetFrom) {
		// reference for interface
		fileOperation.doOperation(propertiesData, fileWriteInto, fileGetFrom);
	}

	// get items for text area for files which will be changed
	private void getForList(PropertiesData propertiesData, File fileWriteInto,
			File fileGetFrom) {

		switch (propertiesData.getRemove()) {
		// if choose copy
		case 0:
			getFileName(new CopyFileOperationHandler(), propertiesData,
					fileWriteInto, fileGetFrom);
			break;
		// if choose move
		case 1:
			getFileName(new MoveFileOperationHandler(), propertiesData,
					fileWriteInto, fileGetFrom);
			break;
		// if choose delete
		case 2:
			getFileName(new RemoveFileOperationHandler(), propertiesData,
					fileWriteInto, fileGetFrom);
			break;
		}
	}

	/**
	 * @param propertiesData
	 * @param fileWriteInto
	 * @param fileGetFrom
	 */
	private void operationChooser(PropertiesData propertiesData,
			File fileWriteInto, File fileGetFrom) {
		// check if file with key & property exists
		if (fileGetFrom.isFile()) {

			// do operation to add key and value and check if they are
			// in it
			int removeLevel = propertiesData.getRemove();
			switch (removeLevel) {
			case 0:
				addProperty(fileWriteInto, propertiesData.getDestKey(),
						getPropertyForKey(fileGetFrom, propertiesData
								.getSourceKey()));
				break;
			case 1:
				addProperty(fileWriteInto, propertiesData.getSourceKey(),
						getPropertyForKey(fileGetFrom, propertiesData
								.getSourceKey()));
				removeProperty(fileGetFrom, propertiesData.getSourceKey());
			case 2:
				removeProperty(fileGetFrom, propertiesData.getSourceKey());
			}
		} else {
			log.warn("Can't find file for getting key & property. File:"
					+ fileGetFrom.toString());
		}
	}

	// check for existing key in the file
	public boolean checkKey(File file, String key) {
		Properties props = new Properties();

		FileInputStream input;
		try {
			input = new FileInputStream(file);
			props.load(input);
			input.close();
		} catch (IOException ie) {
			log.warn("Error while opening file " + file);
		}

		if (props.containsKey(key)) {
			return true;
		} else {
			return false;
		}
	}

	private String getPropertyForKey(File file, String key) {
		String property = null;

		try {
			InputStream input = new FileInputStream(file);

			Properties props = new Properties();
			props.load(input);
			property = props.getProperty(key);

			if (property == null) {
				log.warn("Can't get value for key=" + key + " in file:"
						+ file.toString());
			} else {
				log.info("Success getting value for key=" + key + " in file:"
						+ file.toString());
			}

			input.close();
		} catch (FileNotFoundException e) {
			log.info("Can't find file for getting property for key=" + key
					+ " in file:" + file.toString());
		} catch (IOException e) {
			log.error("Input/output error while getting key=" + key
					+ " from file:" + file.toString());
		}

		return property;
	}

}
